/**
 * This file is part of veraPDF Library core, a module of the veraPDF project.
 * Copyright (c) 2015-2025, veraPDF Consortium <info@verapdf.org>
 * All rights reserved.
 *
 * veraPDF Library core is free software: you can redistribute it and/or modify
 * it under the terms of either:
 *
 * The GNU General public license GPLv3+.
 * You should have received a copy of the GNU General Public License
 * along with veraPDF Library core as the LICENSE.GPL file in the root of the source
 * tree.  If not, see http://www.gnu.org/licenses/ or
 * https://www.gnu.org/licenses/gpl-3.0.en.html.
 *
 * The Mozilla Public License MPLv2+.
 * You should have received a copy of the Mozilla Public License along with
 * veraPDF Library core as the LICENSE.MPL file in the root of the source tree.
 * If a copy of the MPL was not distributed with this file, you can obtain one at
 * http://mozilla.org/MPL/2.0/.
 */
package org.verapdf.features.objects;

import org.verapdf.core.FeatureParsingException;
import org.verapdf.features.FeatureObjectType;
import org.verapdf.features.FeaturesData;
import org.verapdf.features.tools.ColorComponent;
import org.verapdf.features.tools.CreateNodeHelper;
import org.verapdf.features.tools.ErrorsHelper;
import org.verapdf.features.tools.FeatureTreeNode;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * Feature object for outlines part of the features report
 *
 * @author Maksim Bezrukov
 */
public class OutlinesFeaturesObject extends FeaturesObject {

	private static final String OUTLINES = "outlines";

	/**
	 * Constructs new outlines feature object.
	 *
	 * @param adapter outlines adapter class represents document object
	 */
	public OutlinesFeaturesObject(OutlinesFeaturesObjectAdapter adapter) {
		super(adapter);
	}

	/**
	 * @return OUTLINES instance of the FeatureObjectType enumeration
	 */
	@Override
	public FeatureObjectType getType() {
		return FeatureObjectType.OUTLINES;
	}

	/**
	 * Reports all features from the object into the collection
	 *
	 * @return FeatureTreeNode class which represents a root node of the
	 * constructed collection tree
	 * @throws FeatureParsingException occurs when wrong features tree node constructs
	 */
	@Override
	public FeatureTreeNode collectFeatures() throws FeatureParsingException {
		OutlinesFeaturesObjectAdapter outlinesAdapter = (OutlinesFeaturesObjectAdapter) this.adapter;
		FeatureTreeNode root = FeatureTreeNode.createRootNode(OUTLINES);
		Set<Integer> itemsNumbers = new HashSet<>();
		for (OutlinesFeaturesObjectAdapter.OutlineFeaturesObjectAdapter item : outlinesAdapter.getChildren()) {
			Integer keyNumber = item.getKeyNumber();
			if (keyNumber != null && !itemsNumbers.contains(keyNumber)) {
				itemsNumbers.add(keyNumber);
				createItem(item, root, itemsNumbers);
			}
		}
		return root;
	}

	private void createItem(OutlinesFeaturesObjectAdapter.OutlineFeaturesObjectAdapter item,
								   FeatureTreeNode root, Set<Integer> items) throws FeatureParsingException {
		FeatureTreeNode itemNode = root.addChild("outline");

		CreateNodeHelper.addNotEmptyNode("title", item.getTitle(), itemNode);

		FeatureTreeNode color = itemNode.addChild("color");
		double[] clr = item.getColor();
		if (clr != null) {
			color.setAttributes(ColorComponent.RGB_COMPONENTS.createAttributesMap(clr));
		} else {
			registerNewError("Color must be in rgb form");
		}


		FeatureTreeNode style = itemNode.addChild("style");
		style.setAttribute("italic", String.valueOf(item.isItalic()));
		style.setAttribute("bold", String.valueOf(item.isBold()));

		for (OutlinesFeaturesObjectAdapter.OutlineFeaturesObjectAdapter child : item.getChildren()) {
			Integer keyNumber = child.getKeyNumber();
			if (keyNumber != null && !items.contains(keyNumber)) {
				createItem(child, itemNode, items);
			}
		}
	}

	@Override
	public FeaturesData getData() {
		return null;
	}

	static List<Feature> getFeaturesList() {
		// Only errors of top level node
		List<Feature> featuresList = new ArrayList<>();
		featuresList.add(new Feature("Error IDs",
				generateAttributeXPath(OUTLINES, ErrorsHelper.ERRORID), Feature.FeatureType.STRING));
		return featuresList;
	}
}
